package com.xm.security.utils;

import com.xm.common.utils.StrPool;
import com.xm.security.config.properties.JwtProperties;
import com.xm.security.config.security.SecurityConfig;
import io.jsonwebtoken.*;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AccountExpiredException;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @author yousj
 * @version 1.0.0
 * @since 2021/6/16 11:04
 */
@Component
@RequiredArgsConstructor
@EnableConfigurationProperties(JwtProperties.class)
@ConditionalOnClass(SecurityConfig.class)
public class JwtUtil {

    private final JwtProperties jwtProperties;
    private final RedisTemplate redisTemplate;

    public String createJwtToken(String username) {
        Date date = new Date();
        JwtBuilder builder = Jwts.builder()
                .setSubject(username)
                .setIssuedAt(date)
                .signWith(SignatureAlgorithm.HS256, jwtProperties.getSignKey())
                .claim(StrPool.UUID, UUID.randomUUID().toString());
        // 设置JWT为永不过期, 使用redis进行过期时间维护
        builder.setExpiration(DateUtils.addMilliseconds(date, Integer.MAX_VALUE));
        String jwtToken = builder.compact();
        redisTemplate.opsForValue().set(jwtProperties.getSignKey() + username, jwtToken, jwtProperties.getExpire(), TimeUnit.MILLISECONDS);
        return jwtToken;
    }

    public String paresJwtToken(String jwtToken) {
        String subject = getSubject(jwtToken);
        String key = jwtProperties.getSignKey() + subject;
        redisTemplate.opsForValue().set(key, Optional.ofNullable(redisTemplate.opsForValue().get(key)).orElseThrow(() -> new AccountExpiredException(StrPool.EMPTY)), jwtProperties.getExpire(), TimeUnit.MILLISECONDS);
        return subject;
    }

    public String getSubject(String jwtToken) {
        return Jwts.parser().setSigningKey(jwtProperties.getSignKey()).parseClaimsJws(jwtToken).getBody().getSubject();
    }

    public boolean removeToken(String subject) {
        return redisTemplate.delete(jwtProperties.getSignKey() + subject);
    }

}
